/**
 * Title :	jFamilyTree generator
 * Description: jFamilyTree generator
 * Version:	provider
 * Copyright (c) 2001-2008
 * Terms of use:see license agreement at http://treebolic.sourceforge.net/en/license.htm
 * Author: Bernard Bou
 * Company: bsys
 */
package jFamilyTree.generator.tree;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.JScrollPane;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import jFamilyTree.generator.Controller;
import jFamilyTree.model.IEdge;
import jFamilyTree.model.MenuItem;
import jFamilyTree.model.TreeMutableEdge;
import jFamilyTree.model.TreeMutableNode;

/**
 * Tree view
 * 
 * @author Bernard Bou
 */
public class TreeView extends JScrollPane
{
	private static final long serialVersionUID = 1L;

	// D A T A

	/**
	 * Tree component
	 */
	private Tree theTree;

	/**
	 * Dirty flag
	 */
	public boolean dirty;

	// C O N S T R U C T O R

	/**
	 * Constructor
	 */
	public TreeView()
	{
		theTree = new Tree();
		this.setViewportView(theTree);
	}

	// C O N N E C T

	/**
	 * Connect to controller
	 * 
	 * @param thisController
	 *        controller
	 */
	public void connect(Controller thisController)
	{
		theTree.connect(thisController);
	}

	// M O D E L

	/**
	 * Set tree model
	 * 
	 * @param thisTreeModel
	 */
	public void set(TreeModel thisTreeModel)
	{
		// add listener to tree model
		if (thisTreeModel != null)
		{
			thisTreeModel.addTreeModelListener(new TreeModelListener()
			{
				public void treeNodesChanged(TreeModelEvent thisEvent)
				{
					dirty = true;
				}

				public void treeNodesInserted(TreeModelEvent thisE)
				{
					dirty = true;
				}

				public void treeNodesRemoved(TreeModelEvent thisE)
				{
					dirty = true;
				}

				public void treeStructureChanged(TreeModelEvent thisE)
				{
					dirty = true;
				}
			});
		}
		theTree.setModel(thisTreeModel);

		// visibility
		if (thisTreeModel != null)
			theTree.expandAll();
	}

	/**
	 * Add object
	 */
	public void editAdd()
	{
		// selected tree node
		TreePath thisParentPath = theTree.getSelectionPath();
		if (thisParentPath == null)
			return;

		// parent tree node
		DefaultMutableTreeNode thisParentTreeNode = (DefaultMutableTreeNode) thisParentPath.getLastPathComponent();
		if (thisParentTreeNode == null)
			return;

		// parent's number of children
		int thisPos = thisParentTreeNode.getChildCount();

		// object
		Object thisObject = thisParentTreeNode.getUserObject();
		if (thisObject instanceof jFamilyTree.model.MutableNode)
		{
			// parent
			TreeMutableNode thisParentNode = (TreeMutableNode) thisObject;

			// id
			String thisId = TreeMutableNode.makeNodeId();

			// label
			String thisLabel = thisParentNode.getLabel();
			if (thisLabel == null)
				thisLabel = ""; //$NON-NLS-1$
			else
				thisLabel += "-"; //$NON-NLS-1$
			thisLabel += thisPos;

			// new node (handle parent with addToParent)
			TreeMutableNode thisNode = new TreeMutableNode(null, thisId);
			thisNode.setLabel(thisLabel);

			// object add to parent
			thisNode.addToParent(thisParentNode);

			// new tree node
			DefaultMutableTreeNode thisTreeNode = new DefaultMutableTreeNode();
			thisTreeNode.setUserObject(thisNode);

			// tree add to parent
			theTree.addToParent(thisParentTreeNode, thisTreeNode);
		}
		else if (thisObject instanceof EdgesWrapper)
		{
			EdgesWrapper thisWrapper = (EdgesWrapper) thisObject;
			List<IEdge> thisEdgeList = thisWrapper.theEdgeList;
			if (thisEdgeList == null)
			{
				thisEdgeList = new ArrayList<IEdge>();
				thisWrapper.theEdgeList = thisEdgeList;
				thisWrapper.theModel.theTree.setEdges(thisEdgeList);
			}

			// new edge
			TreeMutableEdge thisEdge = new TreeMutableEdge(null, null);

			// object add
			thisEdgeList.add(thisEdge);

			// new tree node
			DefaultMutableTreeNode thisTreeNode = new DefaultMutableTreeNode();
			thisTreeNode.setUserObject(thisEdge);

			// tree add to parent
			theTree.addToParent(thisParentTreeNode, thisTreeNode);
		}
		else if (thisObject instanceof MenuWrapper)
		{
			MenuWrapper thisWrapper = (MenuWrapper) thisObject;
			List<MenuItem> thisMenu = thisWrapper.theMenu;
			if (thisMenu == null)
			{
				thisMenu = new ArrayList<MenuItem>();
				thisWrapper.theMenu = thisMenu;
				thisWrapper.theSettings.theMenu = thisMenu;
			}

			// new menu item
			MenuItem thisMenuItem = new MenuItem();

			// object add
			thisMenu.add(thisMenuItem);

			// new tree node
			DefaultMutableTreeNode thisTreeNode = new DefaultMutableTreeNode();
			thisTreeNode.setUserObject(new MenuItemWrapper(thisMenuItem, thisWrapper.theSettings));

			// tree add to parent
			theTree.addToParent(thisParentTreeNode, thisTreeNode);
		}
	}

	/**
	 * Remove object
	 */
	public void editRemove()
	{
		// selected tree node
		TreePath thisPath = theTree.getSelectionPath();
		if (thisPath == null)
			return;
		DefaultMutableTreeNode thisTreeNode = (DefaultMutableTreeNode) thisPath.getLastPathComponent();
		if (thisTreeNode == null)
			return;

		// parent tree node
		DefaultMutableTreeNode thisParentTreeNode = (DefaultMutableTreeNode) thisTreeNode.getParent();
		if (thisParentTreeNode == null)
			return;

		// object remove
		Object thisObject = thisTreeNode.getUserObject();
		Object thisParentObject = thisParentTreeNode.getUserObject();
		if (thisParentObject instanceof TreeMutableNode)
		{
			TreeMutableNode thisNode = (TreeMutableNode) thisObject;
			thisNode.removeFromParent();
		}
		else if (thisParentObject instanceof EdgesWrapper)
		{
			EdgesWrapper thisWrapper = (EdgesWrapper) thisParentObject;
			thisWrapper.theEdgeList.remove(thisObject);
		}
		else if (thisParentObject instanceof MenuWrapper)
		{
			MenuWrapper thisMenuWrapper = (MenuWrapper) thisParentObject;
			MenuItemWrapper thisMenuItemWrapper = (MenuItemWrapper) thisObject;
			thisMenuWrapper.theMenu.remove(thisMenuItemWrapper.theMenuItem);
		}
		else
		{
			return;
		}

		// tree remove
		theTree.removeFromParent(thisTreeNode);
	}

	/**
	 * Search for tree node whose user object has given class name
	 * 
	 * @param thisClassName
	 *        class name
	 * @return tree node
	 */
	public DefaultMutableTreeNode search(String thisClassName)
	{
		TreeModel thisModel = theTree.getModel();
		DefaultMutableTreeNode thisNode = (DefaultMutableTreeNode) thisModel.getRoot();
		return search(thisNode, thisClassName);
	}

	// S E A R C H

	/**
	 * Search for tree node whose user object has given class name
	 * 
	 * @param thisNode
	 *        start node
	 * @param thisClassName
	 *        class name
	 * @return tree node
	 */
	@SuppressWarnings("unchecked") //$NON-NLS-1$
	private DefaultMutableTreeNode search(DefaultMutableTreeNode thisNode, String thisClassName)
	{
		if (thisNode.getUserObject().getClass().getName().endsWith(thisClassName))
			return thisNode;

		for (Enumeration<DefaultMutableTreeNode> theseChildren = (Enumeration<DefaultMutableTreeNode>) thisNode.children(); theseChildren.hasMoreElements();)
		{
			DefaultMutableTreeNode thisChild = theseChildren.nextElement();
			DefaultMutableTreeNode thisResult = search(thisChild, thisClassName);
			if (thisResult != null)
				return thisResult;
		}
		return null;
	}

	// S E L E C T

	/**
	 * Select tree node
	 * 
	 * @param thisNode
	 *        node
	 */
	public void select(DefaultMutableTreeNode thisNode)
	{
		TreePath thisPath = new TreePath(thisNode.getPath());
		theTree.setSelectionPath(thisPath);
	}

	// E X P A N D / C O L L A P S E

	/**
	 * Expand
	 */
	public void expand()
	{
		theTree.expandAll();
	}

	/**
	 * Collapse
	 */
	public void collapse()
	{
		theTree.collapseAll();
	}
}
